﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Leadtools;
using Leadtools.Controls;
using Leadtools.Codecs;
using Leadtools.Annotations.Automation;
using Leadtools.Annotations.Wpf;
using Leadtools.Annotations.Engine;
using System.IO;
using Model.Modules;
using ViewModel;
using System.Configuration;
using System.Diagnostics;
using C1.WPF;
using Utility;
using Leadtools.ImageProcessing;
using static SteelDetection.UIControl.UCAnnoViewer;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Media3D;
using Proxy;
using Google.Protobuf.WellKnownTypes;



namespace SteelDetection.UIControl
{

    public partial class UCImgViewer : UserControl
    {

        // Declare these global members 
        private ImageViewer viewer;
        private ImageViewerAutomationControl automationControl;
        private AnnAutomationManager annAutomationManager;
        private AnnAutomation automation;
        private ImageViewerPanZoomInteractiveMode _panZoomInteractiveMode;
        private AutomationInteractiveMode _automationInteractiveMode;
        private LightContrastInteractiveMode _lightcontrastInteractiveMode;

        double scale = 0;
        RasterCodecs codecs = new RasterCodecs();
        double zoomrate;

        //解决remote desktop断开重连时，leadtools D2D渲染错误问题
        bool ViewerIsloaded = false;
        Stopwatch sw = new Stopwatch();
        public UCImgViewer()
        {


            InitializeComponent();
            root.DataContext = this;
            //不重新加载
            InitViewer();
            //组件重新初始化需要消耗性能。可以解决解决remote desktop断开重连时，leadtools D2D渲染错误问题
            Loaded += (s, e) =>
            {
                //InitViewer();

            };
            Unloaded += (s, e) =>
            {
                //DisposeViewer();

            };
            Logger.Info("InitViewerSuccess");

            this.SetBinding(ImageInfoProperty, "ImageInfo");
        }




        public Imagedefectinfo ImageInfo
        {
            get { return (Imagedefectinfo)GetValue(ImageInfoProperty); }
            set { SetValue(ImageInfoProperty, value); }
        }
        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageInfoProperty = DependencyProperty.RegisterAttached("ImageInfo", typeof(Imagedefectinfo), typeof(UCImgViewer), new FrameworkPropertyMetadata(null, new PropertyChangedCallback((d, e) =>
        {
            (d as UCImgViewer).SetImageInfo();
            //if (e.NewValue != null&& (e.NewValue as Imagedefectinfo).CurrentImage != null&& (e.NewValue as Imagedefectinfo).CurrentImage.camera_id>0)
            //{
            //    Console.WriteLine((e.NewValue as Imagedefectinfo).CurrentImage.camera_id);
            //    if (e.OldValue==null||(e.NewValue as Imagedefectinfo).CurrentImage.id != (e.OldValue as Imagedefectinfo).CurrentImage.id)

            //}
        })));

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TitleProperty = DependencyProperty.RegisterAttached("Title", typeof(string), typeof(UCImgViewer), new FrameworkPropertyMetadata(""));


        public image_defect CurrentDefect
        {
            get
            {
                return (image_defect)GetValue(CurrentDefectProperty);
            }
            set
            {
                SetValue(CurrentDefectProperty, value);
                var df = this.DataContext;

            }
        }
        public static readonly DependencyProperty CurrentDefectProperty = DependencyProperty.RegisterAttached("CurrentDefect", typeof(image_defect), typeof(UCImgViewer), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback((d, e) =>
        {

        })));




        public Visibility HeaderVisibility
        {
            get { return (Visibility)GetValue(HeaderVisibilityProperty); }
            set { SetValue(HeaderVisibilityProperty, value); }
        }
        public static readonly DependencyProperty HeaderVisibilityProperty = DependencyProperty.RegisterAttached("HeaderVisibility", typeof(Visibility), typeof(UCSteel), new FrameworkPropertyMetadata(Visibility.Visible, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));




        public ImageViewer Viewer { get => viewer; set => viewer = value; }




        private void InitViewer()
        {
            Stopwatch sw = Stopwatch.StartNew();
            // Initialize Image Viewer Object 
            try
            {
                Viewer = new ImageViewer()
                {
                    Background = new SolidColorBrush(Colors.Transparent),
                    ViewPadding = new ControlPadding(),
                    ViewHorizontalAlignment = ControlAlignment.Center,
                    ViewVerticalAlignment = ControlAlignment.Center,
                };
                zoomrate = 1;
                Viewer.Zoom(ControlSizeMode.FitAlways, zoomrate, Viewer.DefaultZoomOrigin);


                // Initialize Automation Control for Image Viewer 
                automationControl = new ImageViewerAutomationControl
                {
                    ImageViewer = Viewer
                };


                // Initialize the Interactive Move for the Image Viewer 
                //AutomationInteractiveMode automationInteractiveMode = new AutomationInteractiveMode
                //{
                //    AutomationControl = automationControl
                //};
                //var panzoommode = new ImageViewerPanZoomInteractiveMode() { };
                //// Add the Interactive Mode to the Image Viewer 
                //Viewer.InteractiveModes.BeginUpdate();
                //Viewer.InteractiveModes.Add(automationInteractiveMode);
                //Viewer.InteractiveModes.Add(panzoommode);
                //Viewer.InteractiveModes.EndUpdate();

                _panZoomInteractiveMode = new ImageViewerPanZoomInteractiveMode();
                _automationInteractiveMode = new AutomationInteractiveMode();
                _lightcontrastInteractiveMode = new LightContrastInteractiveMode();

                ImageViewerInteractiveMode[] modes =
                {
                        _automationInteractiveMode,
                        _panZoomInteractiveMode,
                        _lightcontrastInteractiveMode
                };
                Viewer.InteractiveModes.BeginUpdate();
                foreach (var mode in modes)
                {
                    mode.IsEnabled = false;

                    mode.AutoItemMode = ImageViewerAutoItemMode.None;
                    Viewer.InteractiveModes.Add(mode);
                }
                _panZoomInteractiveMode.IsEnabled = true;
                Viewer.InteractiveModes.EndUpdate();



                //Viewer.DefaultInteractiveMode = panzoommode;
                Viewer.ScrollMode = ControlScrollMode.Hidden;

                viewerGrid.Children.Clear();
                viewerGrid.Children.Add(Viewer);


                Viewer.PreviewMouseDoubleClick += Viewer_MouseLeftButtonDown;
                Viewer.PreviewMouseWheel += Viewer_PreviewMouseWheel;
                annAutomationManager = new AnnAutomationManager
                {
                    RestrictDesigners = true,
                };

                annAutomationManager.CreateDefaultObjects();
                _automationInteractiveMode.AutomationControl = automationControl;
                annAutomationManager.CurrentObjectId = AnnObject.RectangleObjectId;
                AutomationManagerHelper managerHelper = new AutomationManagerHelper(annAutomationManager);
                managerHelper.AutomationManager.CurrentObjectIdChanged += (ss, ee) =>
                {
                    if (annAutomationManager.CurrentObjectId == AnnObject.RulerObjectId)
                    {
                        Viewer.InteractiveModes[0].IsEnabled = true;
                        Viewer.InteractiveModes[1].IsEnabled = false;
                    }
                    else if (annAutomationManager.CurrentObjectId == AnnObject.SelectObjectId)
                    {
                        setViewerInteractiveMode(InteractiveModeName.PanZoom);
                        panmodebtn.IsChecked = true;
                    }
                };
                managerHelper.CreateToolBar();
                var imgtoobar = managerHelper.ToolBar;


                // Set up the Automation (it will create the Container as well) 
                automation = new AnnAutomation(annAutomationManager, automationControl)
                {
                    // Set this Automation as the active one 
                    Active = true,
                };
                var cameras = CameraList.GetInstance();
                double rulerscale = 1;
                if (cameras != null && cameras.Any() && cameras[0].spacing != null)
                    rulerscale = (double)cameras[0].spacing;
                automation.Container.Mapper.Calibrate(new LeadLengthD(4.78125 / (double)rulerscale), AnnUnit.Pixel, new LeadLengthD(1), AnnUnit.Millimeter);
                var sc = automation.Container.Mapper.CalibrationScale;
                automation.Container.UserMode = AnnUserMode.Render;

                Viewer.Loaded += (s, e) =>
                {
                    ViewerIsloaded = true;
                    //SetImageInfo();
                };
                Logger.Info("InitViewerSuccessed");

            }
            catch (Exception e)
            {
                Logger.Info("初始化Viewer失败");
                Logger.Error(e);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds.ToString());
        }

        private void Viewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            var mousept = Mouse.GetPosition(Viewer);
            if (e.Delta > 0)
            {
                if (zoomrate < 8)
                    zoomrate = zoomrate * 2;
            }
            else
            {
                if (zoomrate > 0.5)
                    zoomrate = zoomrate / 2;
            }
            Viewer.Zoom(ControlSizeMode.FitAlways, zoomrate, new LeadPoint((int)mousept.X, (int)mousept.Y));
            UpdateScaleRuler();
        }

        private void DisposeViewer()
        {
            ViewerIsloaded = false;
            Logger.Info("DisposeViewer");
            automation = null;
            annAutomationManager = null;
            Viewer.Dispose();
            Viewer = null;
        }

        private void Viewer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) return;
            var point = e.GetPosition(Viewer);
            var p = automation.Container.Mapper.PointToContainerCoordinates(new LeadPointD(point.X, point.Y));
            var annolist = automation.Container.HitTestPoint(p);
            if (annolist.Length > 0)
            {
                if ((annolist[0] as AnnRectangleObject).Tag == null)
                    return;
                var defect = (annolist[0] as AnnRectangleObject).Tag as image_defect;
                CurrentDefect = defect;
                new VM_WindowDefectInfoDlg(CurrentDefect).ShowDialog();
                //C1MessageBox.Show("缺陷坐标:\tx:" + defect.x + "\ty:" + defect.y + "\n\t\tw:" + defect.w + "\th:" + defect.h + "\n\n缺陷分级:\t" + defect.dtype, "缺陷信息", (C1MessageBoxIcon)(3-defect.dtype));

            }
        }
        Defectypes defectypes = Defectypes.GetInstance();
        private string getColorByType(int id)
        {
            var list = defectypes.Where(t => t.id == id);
            if (list.Count() == 1)
                return list.First().color;

            return "White";
        }

        private async void DrawAnno(Imagedefectinfo imagedefectinfo)
        {
            if (imagedefectinfo == null) return;
            string currentid = "";
            if (imagedefectinfo.CurrentDefect != null)
                currentid = imagedefectinfo.CurrentDefect.id;
            foreach (var defect in imagedefectinfo.Image_DefectList.Where(t => t.is_user_delete != true))
            {
                await Task.Run(() =>
                {
                    bool iscurrentdefect = !string.IsNullOrEmpty(currentid) && defect.id == currentid;
                    string color = getColorByType((int)defect.type);

                    AnnRectangleObject annRectangle = new AnnRectangleObject();
                    annRectangle.Rect = new LeadRectD((double)defect.x * scale, (double)defect.y * scale, (double)defect.w * scale, (double)defect.h * scale);

                    annRectangle.Fill = AnnSolidColorBrush.Create("Transparent");
                    AnnSolidColorBrush borderbrush = new AnnSolidColorBrush();
                    borderbrush.Color = color;

                    annRectangle.Stroke = AnnStroke.Create(borderbrush, LeadLengthD.Create(iscurrentdefect ? 4 : 1));
                    annRectangle.Stroke.StrokeDashArray = defect.confidence == 1 ? new double[] { 1, 0 } : new double[] { 5, 5 };
                    annRectangle.Tag = defect;


                    Viewer.ConvertPoint(Viewer.ActiveItem, ImageViewerCoordinateType.Content, ImageViewerCoordinateType.Control, new LeadPointD(annRectangle.Rect.X, annRectangle.Rect.Y));
                    AnnTextObject anntext = new AnnTextObject();
                    anntext.Rect = new LeadRectD(annRectangle.Rect.X, annRectangle.Rect.Y - 300, 1500, 300);
                    var defectype = defectypes.Where(t => t.id == defect.type).FirstOrDefault();
                    anntext.Text = defectype != null ? defectype.name : "未知";
                    var width = automation.Container.Bounds.Width / 3000;
                    anntext.Font.FontSize = 24;
                    anntext.TextForeground = borderbrush;
                    if (iscurrentdefect)
                    {
                        anntext.TextForeground = new AnnSolidColorBrush() { Color = "#FFFFFF" };
                        anntext.TextBackground = borderbrush;

                    }
                    anntext.Stroke.StrokeThickness = LeadLengthD.Create(0);

                    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        automation.Container.Children.Add(annRectangle);
                        automation.Container.Children.Add(anntext);

                    }));
                });
            }
            await Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                automationControl.AutomationInvalidate(new LeadRectD());
            }));

        }
        CameraList cameras = CameraList.GetInstance();
        private void UpdateScaleRuler()
        {
            if (Viewer.Image != null)
            {
                double scale = Viewer.XScaleFactor;
                var mm_per_pixel = (double)cameras[0].spacing / scale;
                DrawScale(scaleCVS, mm_per_pixel);
                zoomRateLable.Text = (zoomrate * 100).ToString("0") + "%";
            }
        }
        private void DrawScale(Canvas canvas, double mm_per_pixel)
        {
            double length = 1;
            double pixel = 1 / mm_per_pixel;

            while (pixel < 60)
            {
                switch (length.ToString().Substring(0, 1))
                {
                    case "1":
                        length *= 2;
                        pixel *= 2;
                        break;
                    case "2":
                        length *= 2.5;
                        pixel *= 2.5;
                        break;
                    case "5":
                        length *= 2;
                        pixel *= 2;
                        break;
                }
            }
            while (pixel > 151)
            {
                switch (length.ToString().Substring(0, 1))
                {
                    case "1":
                        length /= 2;
                        pixel /= 2;
                        break;
                    case "2":
                        length /= 2.5;
                        pixel /= 2.5;
                        break;
                    case "5":
                        length /= 2;
                        pixel /= 2;
                        break;
                }
            }


            // 清空Canvas
            canvas.Children.Clear();

            // 创建比例尺线条
            Line scaleLine = new Line
            {
                X1 = 0,  // 起点X坐标
                Y1 = 18,  // 起点Y坐标
                X2 = 0 + pixel,  // 终点X坐标，长度为指定像素值
                Y2 = 18,  // 终点Y坐标
                Stroke = Brushes.White,  // 线条颜色
                StrokeThickness = 2  // 线条粗细
            };
            scaleLine.Stretch = Stretch.None;
            canvas.Children.Add(scaleLine);

            // 添加刻度线 - 左侧刻度
            Line leftTick = new Line
            {
                X1 = 0,  // 刻度起点与主线左端对齐
                Y1 = 15,  // 刻度的Y坐标（比主线稍上）
                X2 = 0,  // 刻度终点X与起点相同，垂直方向
                Y2 = 20,  // 刻度终点Y坐标（比主线稍下）
                Stroke = Brushes.White,  // 刻度颜色
                StrokeThickness = 2  // 刻度线条粗细
            };
            canvas.Children.Add(leftTick);

            // 添加刻度线 - 右侧刻度
            Line rightTick = new Line
            {
                X1 = 0 + pixel,  // 刻度起点与主线右端对齐
                Y1 = 15,  // 刻度的Y坐标（比主线稍上）
                X2 = 0 + pixel,  // 刻度终点X与起点相同，垂直方向
                Y2 = 20,  // 刻度终点Y坐标（比主线稍下）
                Stroke = Brushes.White,  // 刻度颜色
                StrokeThickness = 2  // 刻度线条粗细
            };
            canvas.Children.Add(rightTick);

            // 创建文字标签，标明实际长度
            TextBlock lengthLabel = new TextBlock
            {
                Text = GetFormattedLength(length),  // 显示的文字
                FontSize = 14,  // 字体大小
                Foreground = Brushes.White  // 字体颜色
            };

            // 设置文字位置
            Canvas.SetLeft(lengthLabel, 5);  // 与线条起点对齐
            Canvas.SetTop(lengthLabel, 0);   // 文字位于线条上方

            // 将文字添加到Canvas中
            canvas.Children.Add(lengthLabel);

        }
        private string GetFormattedLength(double length)
        {
            if (length >= 1000)  // 大于等于1000毫米，转换为米
            {
                return $"{length / 1000} 米";
            }
            else if (length >= 100)  // 大于等于100毫米，转换为分米
            {
                return $"{length / 100} 分米";
            }
            else if (length >= 10)  // 大于等于10毫米，转换为厘米
            {
                return $"{length / 10} 厘米";
            }
            else  // 小于10毫米，使用毫米
            {
                return $"{length} 毫米";
            }
        }


        private async void SetImageInfo()
        {
            try
            {
                if (!ViewerIsloaded)
                    return;
                Viewer.Image = null;
                automation.Container.Children.Clear();

                if (ImageInfo == null || ImageInfo.CurrentImage == null)
                {
                    return;
                }
                var cameras = CameraList.GetInstance();
                double rulerscale = 1;
                if (cameras != null && cameras.Any() && cameras[0].spacing != null)
                    rulerscale = (double)cameras[0].spacing;
                automation.Container.Mapper.Calibrate(new LeadLengthD(4.78125 / (double)rulerscale), AnnUnit.Pixel, new LeadLengthD(1), AnnUnit.Millimeter);

                RasterImage image = await GetImage();

                if (image != null)
                {
                    Viewer.Image = image;
                    scale = 720 / viewer.Image.XResolution * 1.2;
                    if (automation.Container.Size.Width == 0)
                        automation.Container.Size = automation.Container.Mapper.SizeToContainerCoordinates(LeadSizeD.Create(Viewer.Image.ImageWidth, Viewer.Image.ImageHeight));
                    zoomrate = 1;
                    Viewer.Zoom(ControlSizeMode.FitAlways, zoomrate, Viewer.DefaultZoomOrigin);
                    UpdateScaleRuler();
                    DrawAnno(ImageInfo);
                }
            }
            catch (Exception ee)
            {
                if (ee.Message == "后台缓冲区的设备无效" || ee.InnerException.Message == "后台缓冲区的设备无效")
                {
                    Logger.Info("找到报错：后台缓冲区的设备无效");
                }

                Logger.Error(ee);
                InitViewer();
            }

        }
        private async Task<RasterImage> GetImage()
        {
            if (ImageInfo == null || ImageInfo.CurrentImage == null)
            {
                return null;
            }

            if (ImageInfo.ImageStatus != ImageStatus.Cropped)
            {
                var path = ImageInfo.CurrentImage.image_url.Replace('/', '\\');
                if (ImageInfo.ImageStatus == ImageStatus.Arichived)
                {
                    path = path.Insert(path.IndexOf('\\', 2), "\\backup");
                }
                RasterImage image = null;
                await Task.Run(() =>
                {
                    if (!File.Exists(path))
                        return;
                    try
                    {
                        image = new RasterCodecs().Load(path);
                    }
                    catch (Exception e)
                    {
                        Logger.Error(e);
                    }
                });
                return image;
            }
            else
            {
                var imginfo = ImageInfo.CurrentImage;
                RasterImage backimage = RasterImage.Create(imginfo.width, imginfo.height, 24, 150, new RasterColor(20, 20, 20));
                RasterImage testimage = null;
                if (StaticData.DataBase == DataFrom.Test)
                    testimage = new RasterCodecs().Load(imginfo.image_url);
                foreach (var defect in ImageInfo.Image_DefectList)
                {
                    CombineFastCommand command = new CombineFastCommand();
                    RasterImage overlayimg = null;
                    if (StaticData.DataBase == DataFrom.Test)
                    {
                        CropCommand cropCommand = new CropCommand();
                        cropCommand.Rectangle = new LeadRect((int)defect.crop_x, (int)defect.crop_y, (int)defect.crop_w, (int)defect.crop_h);
                        var cropimage = testimage.Clone();
                        cropCommand.Run(cropimage);
                        overlayimg = cropimage;
                    }
                    else
                    {
                        var path = ImageInfo.CurrentImage.type == 1 ? defect.crop_image_url : (ImageInfo.CurrentImage.type == 2 ? defect.crop_image2_url : defect.crop_image3_url);
                        try
                        {
                            overlayimg = new RasterCodecs().Load(path);
                        }
                        catch (Exception e)
                        {
                            Logger.Error(e);
                            continue;
                        }
                    }
                    command.DestinationImage = backimage;
                    command.DestinationRectangle = new LeadRect((int)defect.crop_x, (int)defect.crop_y, (int)defect.crop_w, (int)defect.crop_h);
                    command.Flags = CombineFastCommandFlags.OperationAdd | CombineFastCommandFlags.Destination0;
                    command.Run(overlayimg);
                }
                return backimage;
            }

        }


        private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {
            toolbar.Visibility = Visibility.Visible;
        }

        private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            toolbar.Visibility = Visibility.Collapsed;
        }

        private void toolbarItem_Click(object sender, RoutedEventArgs e)
        {
            var interactmode = (e.OriginalSource as ToggleButton).Tag.ToString();
            switch (interactmode)
            {
                case "pan":
                    setViewerInteractiveMode(InteractiveModeName.PanZoom);
                    break;
                case "select":
                    setViewerInteractiveMode(InteractiveModeName.Select);
                    break;
                case "anno":
                    setViewerInteractiveMode(InteractiveModeName.Anno);
                    break;
                case "ruler":
                    setViewerInteractiveMode(InteractiveModeName.Ruler);
                    break;
                case "light":
                    setViewerInteractiveMode(InteractiveModeName.LightContrast);
                    break;
                case "label":
                    SetLableVisiable();
                    break;
            }
        }

        public void setViewerInteractiveMode(InteractiveModeName modename)
        {
            Viewer.InteractiveModes.BeginUpdate();
            foreach (var mode in Viewer.InteractiveModes)
            {
                mode.IsEnabled = false;
            }

            switch (modename)
            {
                case InteractiveModeName.PanZoom:
                    Viewer.InteractiveModes[1].IsEnabled = true;
                    break;
                case InteractiveModeName.Select:
                    Viewer.InteractiveModes[0].IsEnabled = true;
                    annAutomationManager.CurrentObjectId = AnnObject.SelectObjectId;
                    break;
                case InteractiveModeName.Anno:
                    Viewer.InteractiveModes[0].IsEnabled = true;
                    annAutomationManager.CurrentObjectId = AnnObject.RectangleObjectId;
                    break;
                case InteractiveModeName.Ruler:
                    Viewer.InteractiveModes[0].IsEnabled = true;
                    annAutomationManager.CurrentObjectId = AnnObject.RulerObjectId;
                    break;
                case InteractiveModeName.LightContrast:
                    Viewer.InteractiveModes[2].IsEnabled = true;
                    break;
            }
            Viewer.InteractiveModes.EndUpdate();
        }

        private void SetLableVisiable()
        {
            automation.Container.Children.Where(t => t is AnnTextObject || t is AnnRectangleObject).All(annotext =>
            {
                annotext.IsVisible = (bool)showlabel.IsChecked;
                return true;
            });
            automationControl.AutomationInvalidate(new LeadRectD());
        }

    }
}
